package com.accedo.achievements.services.ajax.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.accedo.achievements.dataaccess.dao.impl.UserDaoImpl;
import com.accedo.achievements.dataaccess.model.User;
import com.accedo.achievements.services.ajax.UserService;

/**
 * The business logic service of user relevant functionality
 * @author Bo Liang
 *
 */
@Component
public class UserServiceImpl implements UserService {
	
	private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

	private User user; //injection
	private UserDaoImpl userDao; //injection
	
	// Constructor
	UserServiceImpl() {}; 

	/**
	 * Get user's friends with friends' relevant profile information.
	 * @param username	user name
	 * @return			JSON friends<br>
	 * eg. {friends:[{friend_name:'Sebbe', friend_id:'9'},{friend_name:'Peter', friend_id:'8'},
	 * {friend_name:'Johan', friend_id:'7'},{friend_name:'Viktor', friend_id:'6'}]}
	 */
	public JSONObject getJsonFriendsByUsername(String username) {
		log.debug("### Entering getJsonFriendsByUsername(username = {})", username);
		
		List<Integer> fri_idList = new ArrayList<Integer>(); 
		int fri_id; 
		JSONObject jsonObject = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		
		user = userDao.getUserByUsername(username); 
		fri_idList = userDao.getFriendIdListByUserId(user.getId()); 
		
		for (Iterator<Integer> iter = fri_idList.iterator(); iter.hasNext(); ) {
			fri_id = iter.next(); 
			user = userDao.getUserByUserId(fri_id); 
			jsonObject.element("friend_name", user.getUsername()); 
			jsonObject.element("friend_id", user.getId()); 
			jsonArray.add(jsonObject); 
			jsonObject.clear();
		}
		jsonObject.element("friends", jsonArray);
		
		log.debug("### Leaving getJsonFriendsByUsername():{}", jsonObject);
		return jsonObject; 
		
	}
	
	/**
	 * Search the users by using inputString for fuzzy query
	 * <p>the fuzzy query only return the profile of the people who are not this user's friends.
	 * @param username		user name
	 * @param inputString	the input string for fuzzy query
	 * @return				JSON format users<br>
	 * eg. {friends:[{friend_name:'Cristian', friend_id:'13'},{friend_name:'Andres', friend_id:'3'},]}
	 */
	public JSONObject getJsonNoneFriendsByInputString(String username, String inputString) {
		log.debug("### Entering getJsonNoneFriendsByInputString(username = {}, inputString = {})", username, inputString);
		
		List<User> userList = new ArrayList<User>();
		List<Integer> friendIdList = new ArrayList<Integer>();
		JSONObject jsonObject = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		user = userDao.getUserByUsername(username);
		
		// make a user list that contains user and user's friends
		friendIdList = userDao.getFriendIdListByUserId(user.getId());
		friendIdList.add(user.getId());
		
		userList = userDao.getUserListByInputString(inputString);
		
		for (Iterator<User> iter = userList.iterator(); iter.hasNext(); ) {
			user = iter.next();
			// user itself and user's friends can not add into the jsonFriends
			if (!friendIdList.contains(user.getId())) {
				jsonObject.element("friend_name", user.getUsername()); 
				jsonObject.element("friend_id", user.getId()); 
				jsonArray.add(jsonObject); 
				jsonObject.clear();
			}
		}
		jsonObject.element("friends", jsonArray);
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}	
		
		log.debug("### Leaving getJsonNoneFriendsByInputString():{}", jsonObject);
		return jsonObject; 	
	}
	
	/**
	 * Get the specific user's score value.
	 * @param username 	user name
	 * @return 			user score
	 */
	public long getScoreByUsername(String username) {
		log.debug("### Entering getScoreByUsername(username = {})", username);
		long score = -1; 
		user = userDao.getUserByUsername(username); 
		if (user != null) score = user.getScore();
		log.debug("### Leaving getScoreByUsername() : {}", score);
		return score; 
	}
	
	/**
	 * Get the specific user's profile information.
	 * @param username 	user name
	 * @return 			JSON format user<br>
	 * eg. {userid:'1', score:'190', level:'0', username:'Bosse'}
	 */
	public JSONObject getJsonUserByUsername(String username) {
		log.debug("### Entering getJsonUserByUsername(username = {})", username);
		JSONObject jsonObject = new JSONObject();
		user = userDao.getUserByUsername(username); 
		jsonObject.element("userid", user.getId());
		jsonObject.element("score", user.getScore());
		jsonObject.element("level", user.getLevel());
		jsonObject.element("username", user.getUsername());
		log.debug("### Leaving getJsonUserByUsername() : {}", jsonObject);
		return jsonObject; 
	}
	
	/**
	 * Get all users' score value.
	 * @return all users score in Json<br>
	 * eg. {users:[{username:'Sebbe', score:'800'},{username:'Johan', score:'750'},{username:'Viktor', score:'600'},{username:'Thomas', score:'500'}]}
	 */
	public JSONObject getAllJsonUsersScore() {
		log.debug("### Entering getAllJsonUsersScore()");
		JSONObject jsonObject = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		List<User> userList = new ArrayList<User>(); 
		userList = userDao.getUserList(); 
		for(Iterator<User> iter = userList.iterator(); iter.hasNext(); ) {
			user = iter.next(); 
			jsonObject.element("username", user.getUsername()); 
			jsonObject.element("score", user.getScore()); 
			jsonArray.add(jsonObject);
			jsonObject.clear();
		}
		jsonObject.element("users", jsonArray);
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.debug("### Leaving getAllJsonUsersScore() : {}", jsonObject);
		return jsonObject; 
	}

	public User getUser() {
		return user;
	}

	@Resource
	public void setUser(User user) {
		this.user = user;
	}

	public UserDaoImpl getUserDao() {
		return userDao;
	}

	@Resource
	public void setUserDao(UserDaoImpl userDao) {
		this.userDao = userDao;
	}
}
